<?php
/**
 * Cache Method Results
 *
 * @author Zeon <scplay@gmail.com>
 * @date 2018/11/6
 * @copyright PanxSoft Inc.
 */
namespace App\Services\Utils;

use SuperClosure\Serializer;

/**
 * 缓存默认只能针对纯函数
 *
 * 如果闭包要使用 $this， 需要提前绑定
 *
 * Trait Memorable
 * @package App\Services\Utils
 */
Class Memorable
{
    /**
     * memorize your func logic
     *
     * @param callable $function
     *
     * @return callable
     */
    public static function singleton(callable $function): callable
    {
        static $singletons = [];

        // Laravel 使用 SuperClosure\Serializer 对 function 序列化（php serialize 函数是不行的）
        // $function 必须是纯函数 $this 可能会报 Serialization of 'Closure' is not allowed
//        $serial_func = (new Serializer)->serialize($function);
        $serial_func = serialize(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2));

        return $singletons[$serial_func] ?? ($singletons[$serial_func] = self::memorize($function));
    }

    /**
     * @param callable $function
     *
     * @return callable
     */
    public static function memorize(callable $function): callable
    {
        return function (...$args) use ($function) {
            static $results = [];

            $serial_args = serialize($args); // args 中不能出现 closure

            return $results[$serial_args] ?? ($results[$serial_args] = $function(...$args));
        };
    }
}